<?php
declare(strict_types=1);
namespace app\admin\service;

use app\common\Attribute\CodeAnalyzer;
use app\common\traits\ClassMake;
use app\common\traits\ErrorTrait;
use think\facade\Request;
use think\facade\Log;
use think\facade\Db;
class RuleNode
{
    use ClassMake;
    use ErrorTrait;
    public function execute()
    {
        try {
            $this->setError('test');
        } catch (\Exception $e) {
            Log::error($e->getMessage());
            Log::error($e->getTraceAsString());
        }
    }

    private function getAppPath()
    {
        // 获取应用目录下的所有应用
        $appPath = root_path() . 'app/';
        $applications = [];

        foreach (scandir($appPath) as $item) {
            if ($item === '.' || $item === '..' || $item === 'common') {
                continue;
            }

            if (is_dir($appPath . $item) && is_dir($appPath . $item . '/controller')) {
                $applications[$item] = $appPath . $item . '/controller';
            }
        }
        return $applications;
    }
    private function getAppNodes()
    {
        $analyzer = new CodeAnalyzer($this->getAppPath());
        $results = $analyzer->analyze();
        $nodes = [];
        foreach ($results as $appName => $Controllers) {
            $nodes[$appName]['title'] = $appName;
            foreach ($Controllers as $namespace => $controller) {
                $nodes[$appName]['child'][$namespace] = [
                    'namespace' => $namespace,
                    'title' => null,
                ];

                $ClassAttributes = array_column($controller['attributes'], null, 'name');

                if (!empty($ClassAttributes)) {
                    // dump($ClassAttributes['app\\common\\Attribute\\ClassTitle']);

                    if (isset($ClassAttributes['app\\common\\Attribute\\ClassTitle']['arguments'][0])) {
                        $className = $ClassAttributes['app\\common\\Attribute\\ClassTitle']['arguments'][0];
                    } elseif (isset($ClassAttributes['app\\common\\Attribute\\ClassTitle']['arguments']['name'])) {
                        $className = $ClassAttributes['app\\common\\Attribute\\ClassTitle']['arguments']['name'];
                    }
                    $nodes[$appName]['child'][$namespace] = [
                        // 'namespace' => $namespace,
                        'title' => $className,
                    ];
                } else {

                }
                if ($nodes[$appName]['child'][$namespace]['title'] !== null) {
                    foreach ($controller['methods'] as $methodName => $method) {

                        // if ($method['isPublic'] == true && $namespace == 'app\\admin\\controller\\Upload') {
                        $attributes = array_column($method['attributes'], null, 'name');
                        if (!empty($attributes)) {
                            $controllerNode = explode('\\controller\\', $namespace)[1];
                            $controllerNode = strtolower(str_replace('\\', '.', $controllerNode));
                            $methods = $attributes['app\common\Attribute\RequestMethod']['arguments'][0];
                            $methods = explode(',', $methods[0]);
                            foreach ($methods as $method) {
                                $nodes[$appName]['child'][$namespace]['child'][$method] = [
                                    'url' => $appName . '/' . $controllerNode . '/' . $methodName,
                                    'methods' => $method,
                                    'title' => $attributes['app\common\Attribute\RequestTitle']['arguments'][0],
                                ];
                            }

                        }
                    }
                } else {
                    unset($nodes[$appName]['child'][$namespace]);
                }
            }
            if (empty($nodes[$appName]['child'])) {
                unset($nodes[$appName]);
            }
            return $nodes;
        }
    }

    /**
     * 同步权限规则数据到m_system_auth_rule表
     * @param array $authData 包含多个app的权限规则数组
     * @return void
     */
    function syncAuthRulesToDb(array $authData)
    {
        // 遍历每个app节点（顶级节点）
        foreach ($authData as $appKey => $appInfo) {
            $appName = $appInfo['title']; // 当前app的名称
            $controllers = $appInfo['child'] ?? [];

            if (empty($controllers)) {
                continue;
            }

            // 遍历当前app下的所有控制器
            foreach ($controllers as $controllerClass => $controllerInfo) {
                // 1. 处理一级：控制器节点，传入当前app名称
                $controllerId = $this->handleControllerNode($controllerClass, $controllerInfo, $appName);

                // 2. 处理二级：类方法节点
                $methodGroups = $this->groupMethodsByUrl($controllerInfo['child'] ?? []);
                foreach ($methodGroups as $methodUrl => $methodDetail) {
                    $methodId = $this->handleMethodNode($methodUrl, $methodDetail, $controllerId, $controllerClass, $appName);

                    // 3. 处理三级：请求类型节点
                    foreach ($methodDetail['requests'] as $requestInfo) {
                        $this->handleRequestNode($requestInfo, $methodId, $controllerClass, $appName);
                    }
                }
            }
        }
    }

    /**
     * 处理一级控制器节点
     * @param string $controllerClass 控制器类名（如app\admin\controller\Login）
     * @param array $controllerInfo 控制器信息（含title和child）
     * @return int 控制器节点ID
     */
    function handleControllerNode(string $controllerClass, array $controllerInfo, $appName): int
    {
        $request = Request::instance();
        $db = Db::name('system_auth_rule');

        // 提取控制器URL
        $firstMethodUrl = $this->getFirstMethodUrl($controllerInfo['child'] ?? []);
        $controllerUrl = $this->getControllerUrlFromMethodUrl($firstMethodUrl);

        // 构造基础数据（使用当前app名称）
        $data = [
            'app_name' => $appName,  // 直接使用当前app的title
            'title' => $controllerInfo['title'] ?? $controllerClass,
            'url' => $controllerUrl,
            'method' => null,
            'parent_id' => 0,  // 每个app的控制器都是顶级节点
            'update_time' => time(),
            'update_ip' => $request->ip(),
            // 其他字段保持不变...
        ];

        // 查找条件增加app_name，避免不同app间的URL冲突
        $exist = $db->where([
            'app_name' => $appName,
            'url' => $controllerUrl,
            'parent_id' => 0
        ])->find();

        if ($exist) {
            // 存在则更新
            unset($data['app_name']);
            unset($data['url']);
            unset($data['parent_id']);
            $db->where('id', $exist['id'])->update($data);
            return $exist['id'];
        } else {
            // 不存在则新增（补充创建信息）
            $data['create_time'] = time();
            $data['create_ip'] = $request->ip();
            return $db->insertGetId($data);
        }
    }

    /**
     * 处理二级类方法节点
     * @param string $methodUrl 方法URL（如admin/login/captcha）
     * @param array $methodDetail 方法详情（含title和requests）
     * @param int $parentId 父级控制器ID
     * @param string $controllerClass 控制器类名
     * @return int 方法节点ID
     */
    function handleMethodNode(string $methodUrl, array $methodDetail, int $parentId, string $controllerClass, $appName): int
    {
        $request = Request::instance();
        $db = Db::name('system_auth_rule');

        // 构造基础数据
        $data = [
            'app_name' => $appName,
            'title' => $methodDetail['title'] ?? '未命名方法',
            'url' => $methodUrl,
            'method' => NULL, // 方法级method固定为ALL
            'parent_id' => $parentId, // 父ID为控制器ID
            'update_time' => time(),
            'update_ip' => $request->ip(),
            'is_need_auth' => 1,
            'is_system' => 0,
            'listorder' => 100,
            'description' => '自动同步的方法节点：' . $methodUrl,
        ];

        // 查找已存在的记录（按URL和父ID判断）
        $exist = $db->where([
            'app_name' => $appName,
            'url' => $methodUrl,
            'parent_id' => $parentId
        ])->find();

        if ($exist) {
            unset($data['app_name']);
            unset($data['url']);
            unset($data['parent_id']);
            unset($data['method']);
            $db->where('id', $exist['id'])->update($data);
            return $exist['id'];
        } else {
            $data['create_time'] = time();
            $data['create_ip'] = $request->ip();
            return $db->insertGetId($data);
        }
    }

    /**
     * 处理三级请求类型节点（GET/POST等）
     * @param array $requestInfo 请求信息（含url、methods、title）
     * @param int $parentId 父级方法ID
     * @param string $controllerClass 控制器类名
     * @return int 请求节点ID
     */
    function handleRequestNode(array $requestInfo, int $parentId, string $controllerClass, $appName): int
    {
        $request = Request::instance();
        $db = Db::name('system_auth_rule');

        // 构造基础数据
        $data = [
            'app_name' => $appName,
            'title' => isset($requestInfo['title']) ? $requestInfo['title'] . '(' . $requestInfo['methods'] . ')' : '(' . $requestInfo['methods'] . ')',
            'url' => $requestInfo['url'],
            'method' => $requestInfo['methods'], // 请求类型（GET/POST等）
            'parent_id' => $parentId, // 父ID为方法ID
            'update_time' => time(),
            'update_ip' => $request->ip(),
            'is_need_auth' => 1,
            'is_system' => 0,
            'listorder' => 100,
            'description' => '自动同步的请求节点：' . $requestInfo['methods'] . ' ' . $requestInfo['url'],
        ];

        // 查找已存在的记录（按URL、method和父ID判断）
        $exist = $db->where([
            'app_name' => $appName,
            'url' => $requestInfo['url'],
            'method' => $requestInfo['methods'],
            'parent_id' => $parentId
        ])->find();

        if ($exist) {
            unset($data['app_name']);
            unset($data['url']);

            $db->where('id', $exist['id'])->update($data);
            return $exist['id'];
        } else {
            $data['create_time'] = time();
            $data['create_ip'] = $request->ip();
            return $db->insertGetId($data);
        }
    }

    /**
     * 辅助函数：将控制器的子节点按URL分组（聚合同一方法的不同请求类型）
     * @param array $childNodes 控制器的child节点（原始请求类型集合）
     * @return array 分组后的方法集合（键为URL，值含title和requests）
     */
    function groupMethodsByUrl(array $childNodes): array
    {
        $groups = [];
        foreach ($childNodes as $requestType => $requestInfo) {
            $url = $requestInfo['url'];
            // 初始化分组
            if (!isset($groups[$url])) {
                $groups[$url] = [
                    'title' => $requestInfo['title'],
                    'requests' => []
                ];
            }
            // 收集同一方法的不同请求类型
            $groups[$url]['requests'][] = $requestInfo;
        }
        return $groups;
    }

    /**
     * 辅助函数：获取第一个方法的URL（用于解析控制器URL）
     * @param array $childNodes 控制器的child节点
     * @return string 第一个方法的URL
     */
    function getFirstMethodUrl(array $childNodes): string
    {
        if (empty($childNodes)) {
            return '';
        }
        $firstNode = reset($childNodes);
        return $firstNode['url'] ?? '';
    }

    /**
     * 辅助函数：从方法URL中截取控制器URL（去除最后一段方法名）
     * @param string $methodUrl 方法URL（如admin/login/captcha）
     * @return string 控制器URL（如admin/login）
     */
    function getControllerUrlFromMethodUrl(string $methodUrl): string
    {
        $parts = explode('/', $methodUrl);
        if (count($parts) <= 1) {
            return $methodUrl; // 异常情况直接返回原URL
        }
        array_pop($parts); // 移除最后一段（方法名）
        return implode('/', $parts);
    }



}
